/**
 * @file p_queue.c
 * @author Zhaoquan.xiong (zhaoquan@163.com)
 * @brief Implements a priority queue system with multiple priority levels, supporting thread-safe operations.
 *        It provides memory pool management and priority-based queue operations such as enqueue, dequeue, and queries.
 * @version 0.1
 * @date 2025-01-21
 * 
 * @copyright Copyright (c) 2025
 * 
 */
#ifndef _P_QUEUE_H
#define _P_QUEUE_H

#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>

/**
 * @brief Enumeration for queue operation statuses.
 */
typedef enum {
    P_QUEUE_SUCCESS = 0,     /**< Operation successful */
    P_QUEUE_ERROR_FULL,      /**< Queue is full */
    P_QUEUE_ERROR_EMPTY,     /**< Queue is empty */
    P_QUEUE_ERROR_MEMORY,    /**< Memory allocation failed */
    P_QUEUE_ERROR_INVALID    /**< Invalid operation */
} p_queue_status_t;

/**
 * @brief Mutex structure for protecting shared resources.
 *
 * The `locked` flag indicates whether the mutex is currently locked.
 */
typedef struct {
    volatile bool locked;  ///< Mutex lock status
} p_queue_mutex_t;
/**
 * @brief Structure for queue data node (element).
 */
typedef struct {
    int priority;     /**< Element's priority */
    int index;        /**< FIFO order index */
    int data_index;   /**< Index of the data in the memory pool */
} p_queue_data_node_t;

/**
 * @brief Structure for each priority queue.
 */
typedef struct {
    int front;       /**< Front of the queue */
    int rear;        /**< Rear of the queue */
    int size;        /**< Current size of the queue */
    p_queue_data_node_t *queue;  /**< Array to store the queue elements */
} p_queue_node_t;

/**
 * @brief Structure for the priority queue.
 */
typedef struct {
    p_queue_node_t *priority_queues;     /**< Array of priority queues */
    int num_priorities;                  /**< Number of priorities */
    int max_size;                        /**< Maximum size of each priority queue */
    int data_type_size;                  /**< Size of the data type (size of each element) */
    int total_size;                      /**< Total number of elements across all queues */
    void *memory_pool;                   /**< Memory pool to store data */
    bool *memory_pool_used;              /**< Flags to track memory pool usage */
    int memory_pool_size;                /**< Size of the memory pool */
    p_queue_mutex_t queue_mutex;         /**< Lock of queue */
} p_queue_t;

#ifdef __cplusplus
extern "C"{
#endif

/**
 * @brief Creates a priority queue with the specified number of priorities and maximum size.
 *
 * @param num_priorities The number of priorities.
 * @param max_size The maximum size of each priority queue.
 * @param data_type_size The size of the data type.
 * @return A pointer to the created priority queue, or NULL if creation fails.
 */
extern p_queue_t* p_queue_create(int num_priorities, int max_size, int data_type_size);

/**
 * @brief Destroys the priority queue, freeing all allocated memory.
 *
 * @param pq A pointer to the priority queue pointer to destroy.
 */
extern void p_queue_destroy(p_queue_t **pq);

/**
 * @brief Checks if the specified priority queue is empty.
 *
 * @param pq The priority queue object.
 * @param priority The priority level to check.
 * @return true if the queue is empty, false otherwise.
 */
extern bool p_queue_is_empty(p_queue_t *pq, int priority);

/**
 * @brief Checks if the specified priority queue is full.
 *
 * @param pq The priority queue object.
 * @param priority The priority level to check.
 * @return true if the queue is full, false otherwise.
 */
extern bool p_queue_is_full(p_queue_t *pq, int priority);

/**
 * @brief Gets the size of the specified priority queue.
 *
 * @param pq The priority queue object.
 * @param priority The priority level to query.
 * @return The size of the queue, or -1 if the priority is invalid.
 */
extern int p_queue_get_size(p_queue_t *pq, int priority);

/**
 * @brief Gets the total size of all queues combined.
 *
 * @param pq The priority queue object.
 * @return The total size of all queues.
 */
extern int p_queue_get_total_size(p_queue_t *pq);

/**
 * @brief Enqueues data into the priority queue with the specified priority.
 *
 * @param pq The priority queue object.
 * @param data The data to enqueue.
 * @param priority The priority level of the queue to insert data into.
 * @return The status of the operation.
 */
extern p_queue_status_t p_queue_send(p_queue_t *pq, void *data, int priority);

/**
 * @brief Sends data to the highest priority queue (priority 0).
 *
 * @param pq The priority queue object.
 * @param data A pointer to the data to be inserted.
 * @return A status code indicating success or failure.
 */
extern p_queue_status_t p_queue_send_highest_priority(p_queue_t *pq, void *data);


/**
 * @brief Sends data to the lowest priority queue (the last priority).
 *
 * @param pq The priority queue object.
 * @param data A pointer to the data to be inserted.
 * @return A status code indicating success or failure.
 */
extern p_queue_status_t p_queue_send_lowest_priority(p_queue_t *pq, void *data);

/**
 * @brief Dequeues data from the priority queue.
 *
 * @param pq The priority queue object.
 * @param data A pointer to the buffer where the dequeued data will be stored.
 * @return The status of the operation.
 */
extern p_queue_status_t p_queue_receive(p_queue_t *pq, void **data);

/**
 * @brief Peeks at the data from the highest priority queue that contains data, without removing it.
 *
 * @param pq The target priority queue object.
 * @param data A pointer to store the peeked data.
 * @return P_QUEUE_SUCCESS if successful, otherwise returns the corresponding error code.
 */
extern p_queue_status_t p_queue_peek(p_queue_t *pq, void **data);

/**
 * @brief Clears the specified priority queue, freeing all elements in it.
 *
 * @param pq The priority queue object.
 * @param priority The priority level to clear.
 * @return A status code indicating success or failure.
 */
extern p_queue_status_t p_queue_clear(p_queue_t *pq, int priority);

/**
 * @brief Dumps the current status of the priority queue (for debugging purposes).
 *
 * @param pq The priority queue object.
 */
extern void p_queue_dump(p_queue_t *pq);

/**
 * @brief Prints the contents of the priority queues in the priority queue system.
 * 
 * This function iterates through each priority queue in the given priority queue 
 * system and prints the elements in each non-empty queue. Each element's value is 
 * retrieved from the memory pool and printed based on the data index.
 * 
 * @param pq Pointer to the priority queue system (`p_queue_t`).
 * 
 * Each priority queue is printed in the following format:
 * "Priority <priority_number> queue: <element1> <element2> ... <elementN>"
 * 
 * The function assumes that the data stored in the queues are of type `int`, and 
 * accesses the memory pool accordingly.
 */
extern void p_queue_print(p_queue_t *pq);

#ifdef __cplusplus
}
#endif


#endif
